import elasticsearch
from django.shortcuts import render
from django.db.models import Q
from random import sample
from rest_framework.decorators import action
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from rest_framework.mixins import *
from rest_framework.status import HTTP_201_CREATED, HTTP_200_OK, HTTP_404_NOT_FOUND
from rest_framework.permissions import IsAuthenticated
from rest_framework.pagination import LimitOffsetPagination, PageNumberPagination
from elasticsearch import Elasticsearch, exceptions

# Create your views here.
from utils.customPermissions import MyBasePermission, auto_user
from work.models import Label, Topic
from .serializers import *
from config.elasticsearchConfig import HOST, PORT

es = Elasticsearch([{'host': HOST, 'port': PORT}], timeout=3600)


class LabelViewSet(ModelViewSet):
    queryset = Label.objects.all()
    serializer_class = LabelSerializer
    permission_classes = [MyBasePermission]  # 内置登录权限

    @auto_user
    def create(self, request):
        # request.data['user']提交过来的用户id（字符串）
        # 需要修改为当前登录用户的id

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=HTTP_201_CREATED)

    @auto_user
    def update(self, request, pk):  # 标签id
        # 当前登录用户是不是标签的创造者
        if not Label.objects.filter(pk=pk, user=request.user):
            return Response({'msg': '您没有修改权限'})
        label = Label.objects.get(pk=pk, user=request.user)

        serializer = self.get_serializer(label, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=HTTP_200_OK)

    @action(methods=['get'], detail=True)
    def examination(self, request, pk):  # 标签pk
        # 查询标签
        try:
            label = Label.objects.get(pk=pk)
        except Label.DoesNotExist:
            return Response(status=HTTP_404_NOT_FOUND)

        serializer = LabelTopicSerializer(label)
        return Response(serializer.data)


# def destroy(self, request, *args, **kwargs):
#     data = request


class TopicPaginationPageNumber(PageNumberPagination):
    page_size = 5
    max_page_size = 100


class TopicViewSet(ModelViewSet):
    queryset = Topic.objects.filter(is_delete=False)
    serializer_class = TopicSerializer
    permission_classes = [MyBasePermission]
    pagination_class = TopicPaginationPageNumber

    @auto_user
    def create(self, request):
        # request.data['user']提交过来的用户id（字符串）
        # 需要修改为当前登录用户的id

        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # es数据
        res_data = serializer.data
        es.index(index='topic', id=res_data['id'], body=res_data)

        return Response(serializer.data, status=HTTP_201_CREATED)

    @auto_user
    def update(self, request, pk):  # 标签id
        # 当前登录用户是不是题目的创造者
        if not Topic.objects.filter(pk=pk, user=request.user):
            return Response({'msg': '您没有修改权限'})
        topic = Topic.objects.get(pk=pk, user=request.user)

        serializer = self.get_serializer(topic, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        res_data = serializer.data
        es.update(index='topic', id=res_data['id'], body={'doc': res_data})
        return Response(serializer.data, status=HTTP_200_OK)

    def destroy(self, request, *args, **kwargs):
        # 数据库删除
        res_data = ModelViewSet.destroy(self, request, *args, **kwargs)
        es.delete(index='topic', id=kwargs['pk'])
        # es同步
        return res_data

    @action(methods=['get'], detail=False)
    def search(self, request):
        data = dict(request.query_params)
        page = int(data.get('page')[0]) if data.get('page') else 1  # 第几页
        size = int(data.get('size')[0]) if data.get('size') else 5  # 每页显示条数
        subject = data.get('subject')[0] if data.get('subject') else ''  # 题目标题

        '''
        GET /topic/_search
        {
          "query": {"match":{"subject":"python"}},
          "highlight": {
            "fields": {"subject":{}},
            "pre_tags": "<strong style='color:red'>",
            "post_tags": "</strong>"
          },
          "from": 0,
          "size": 2
        }
        '''
        # 构造查询规则
        body = {
            "query": {},  # 是否传值，查询不同
            "highlight": {
                "fields": {"subject": {}},
                "pre_tags": "<strong style='color:red'>",
                "post_tags": "</strong>"
            },
            "from": (page - 1) * size,  # page=1:0; page=2:size page=3:2*size
            "size": size
        }

        if not subject:
            body['query'] = {"match_all": {}}  # 没有搜索目标，查询全部
        else:
            body['query'] = {"match": {"subject": subject}}  # 有搜索目标
        try:
            es_res = es.search(index='topic', body=body)

            # 构造返回数据
            count = es_res['hits']['total']['value']
            subject_keyword = subject if subject else ''
            next = f'http://127.0.0.1:8001/work/topic/search/?page={page + 1}&size={size}&subject={subject_keyword}' if page * size < count else None
            previous = f'http://127.0.0.1:8001/work/topic/search/?page={page - 1}&size={size}&subject={subject_keyword}' if page > 1 else None

            # 替换高亮
            def highlight(i):
                if i.get('highlight'):
                    i['_source']['subject'] = i['highlight']['subject'][0]
                return i['_source']

            results = [highlight(i) for i in es_res['hits']['hits']]
            res = {
                "count": count,
                "next": next,
                "previous": previous,
                "results": results
            }
        except exceptions.NotFoundError:
            res = {
                "count": 0,
                "next": None,
                "previous": None,
                "results": []
            }
        return Response(res)

        # @action(methods=['get'], detail=False)
        # def init(self, request):
        #     """
        #     测试接口，将mysql现有数据，放入ES
        #     项目正式上线时，测试数据会清空
        #     :param request:
        #     :return:
        #     """
        #     serializer = self.get_serializer(self.get_queryset(), many=True)
        #     data = serializer.data
        #     for i in data:
        #         es.index(index='topic', id=i['id'], body=i)
        #     return Response(serializer.data)

        # 分页类


class TopicPagination(LimitOffsetPagination):
    default_limit = 5  # 默认每页5条数据
    max_limit = 20


class TopicStudentViewSet(GenericViewSet, ListModelMixin):
    queryset = Topic.objects.exclude(Q(label__name__contains='考试') | Q(is_delete=True))
    serializer_class = TopicNoAnswerSerializer
    permission_classes = [IsAuthenticated]
    pagination_class = TopicPagination

    @action(methods=['get'], detail=False)
    def random(self, request):
        # 指定数量
        data = dict(request.query_params)
        size = int(data.get('size')[0]) if data.get('size') else 3

        # TopicNoAnswerSerializer(Topic.objects.exclude(Q(label__name__contains='考试') | Q(is_delete=True)))
        serializer = self.get_serializer(self.get_queryset(), many=True)

        # sample(),从指定序列中随机抽取指定数量的数据
        return Response(sample(serializer.data, size))

    @action(methods=['get'], detail=False)
    def search(self, request):
        data = dict(request.query_params)
        offset = int(data.get('offset')[0]) if data.get('offset') else 1  # 从第几条开始
        limit = int(data.get('limit')[0]) if data.get('limit') else 5  # 每页显示条数
        subject = data.get('subject')[0] if data.get('subject') else ''  # 题目标题

        '''
        GET /topic/_search
        {
          "query": {"match":{"subject":"python"}},
          "highlight": {
            "fields": {"subject":{}},
            "pre_tags": "<strong style='color:red'>",
            "post_tags": "</strong>"
          },
          "from": 0,
          "size": 2
        }
        '''
        # 构造查询规则
        body = {
            "query": {
                "bool": {
                    "must_not": [{"match": {"label_name": "考试"}}],  # 去考试题
                    "should": []
                }
            },  # 是否传值，查询不同
            "highlight": {
                "fields": {"subject": {}},
                "pre_tags": "<strong style='color:red'>",
                "post_tags": "</strong>"
            },
            "from": offset,
            "size": limit,
            "_source": {"excludes": ["answer"]}  # 去答案
        }

        if not subject:
            body['query']['bool']['should'].append({"match_all": {}})  # 没有搜索目标，查询全部
        else:
            body['query']['bool']['should'].append({"match": {"subject": subject}})  # 有搜索目标
        try:
            es_res = es.search(index='topic', body=body)

            # 构造返回数据
            count = es_res['hits']['total']['value']
            subject_keyword = subject if subject else ''
            next = f'http://127.0.0.1:8001/work/topics/search/?offset={offset + limit}&limit={limit}&subject={subject_keyword}' if offset + limit < count else None
            previous = f'http://127.0.0.1:8001/work/topics/search/?offset={offset - limit}&limit={limit}&subject={subject_keyword}' if offset > 1 else None

            # 替换高亮
            def highlight(i):
                if i.get('highlight'):
                    i['_source']['subject'] = i['highlight']['subject'][0]
                return i['_source']

            results = [highlight(i) for i in es_res['hits']['hits']]
            res = {
                "count": count,
                "next": next,
                "previous": previous,
                "results": results
            }
        except exceptions.NotFoundError:
            res = {
                "count": 0,
                "next": None,
                "previous": None,
                "results": []
            }
        return Response(res)
